import { createAsyncThunk, createSlice, isRejected } from "@reduxjs/toolkit";
import { Commodity, CommodityEntry, GetParams, PageInfo, int } from "../types";
import { deleteRequest, getRequest, postRequest, putRequest } from "../util/Net";
import { RootState } from "./store";


// 1. Requests.

type GetCommodityRequest = GetParams & {
  name?: string;
};

type CreateCommodityRequest = Commodity;

type UpdateCommodityRequest = CommodityEntry;

interface DeleteCommodityRequest {
  id: string;
}

// 2. Responses.

type GetCommodityResponseEntry = CommodityEntry;

type GetCommodityResponse = PageInfo<GetCommodityResponseEntry>;

// 3. Params for reducers.

type GetCommodityParams = GetCommodityRequest;

type CreateCommodityParams = Commodity;

type UpdateCommodityParams = CommodityEntry;

interface DeleteCommodityParams {
  id: int[];
}

// 4. State and initial value definition.

interface CommodityManagementState {
  loaded: boolean;
  entries: CommodityEntry[];
}

const initialState: CommodityManagementState = {
  loaded: false,
  entries: []
};

// 5. Async functions definition.

const getCommodities = createAsyncThunk('/commodity/get', async (params: GetCommodityParams) => {
  const response = await getRequest<GetCommodityResponse, GetCommodityRequest>({
    url: '/commodity',
    params: params
  });
  return response.data;
});

const createCommodity = createAsyncThunk('/commodity/post', async (params: CreateCommodityParams) => {
  const response = await postRequest<null, CreateCommodityRequest>({
    url: '/commodity',
    request: params
  });
  return response.data;
});

const updateCommodity = createAsyncThunk('/commodity/put', async (params: UpdateCommodityParams) => {
  const response = await putRequest<null, UpdateCommodityRequest>({
    url: `/commodity/${params.id}`,
    request: params
  });
  return response.data;
});

const deleteCommodity = createAsyncThunk('/commodity/delete', async (params: DeleteCommodityParams) => {
  const response = await deleteRequest<null, null, DeleteCommodityRequest>({
    url: '/commodity',
    params: {
      id: params.id.join(',')
    }
  });
  return response.data;
});

// 6. Slice definition.

const commodityManagementSlice = createSlice({
  name: 'commodityManagement',
  initialState: initialState,
  reducers: {
    clear: (state) => {
      state.entries = [];
      state.loaded = false;
    },
    refresh: (state) => {
      state.loaded = false;
    }
  },
  extraReducers: (builder) => {
    builder.addCase(getCommodities.fulfilled, (state, action) => {
      state.entries = action.payload.result.data;
      state.loaded = true;
    }).addCase(createCommodity.fulfilled, (state) => {
      state.loaded = false;
    }).addCase(updateCommodity.fulfilled, (state) => {
      state.loaded = false;
    }).addCase(deleteCommodity.fulfilled, (state) => {
      state.loaded = false;
    }).addMatcher(isRejected, (state, action) => {
      console.error(action.error);
    });
  }
});

export default commodityManagementSlice.reducer;
export const commodityManagementActions = { ...commodityManagementSlice.actions, getCommodities, createCommodity, updateCommodity, deleteCommodity };
export const selectCommodityEntries = (root: RootState) => root.commodityManagementReducer.entries;
export const selectCommodityEntriesLoaded = (root: RootState) => root.commodityManagementReducer.loaded;